package org.zuel.lkq.service.impl;

import com.alibaba.druid.util.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zuel.lkq.component.LoginToken;
import org.zuel.lkq.constant.UserConstant;
import org.zuel.lkq.domain.*;
import org.zuel.lkq.enums.LoginType;
import org.zuel.lkq.enums.RoleEnum;
import org.zuel.lkq.enums.UserStatusEnum;
import org.zuel.lkq.exception.BizException;
import org.zuel.lkq.mapper.UserMapper;
import org.zuel.lkq.mapper.UserRoleMapper;
import org.zuel.lkq.param.auth.LoginParam;
import org.zuel.lkq.param.auth.RegisterParam;
import org.zuel.lkq.service.AuthQueryService;
import org.zuel.lkq.service.UserService;
import org.zuel.lkq.util.ArgumentUtil;
import org.zuel.lkq.util.ResponseUtil;
import org.zuel.lkq.viewmodel.auth.ChildrenRouter;
import org.zuel.lkq.viewmodel.auth.Meta;
import org.zuel.lkq.viewmodel.auth.Router;
import org.zuel.lkq.viewmodel.auth.UserInfo;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    public final UserMapper userMapper;

    public final UserRoleMapper userRoleMapper;

    public final AuthQueryService authQueryService;

    private static final String LAYOUT = "Layout";

    @Autowired
    public UserServiceImpl(UserMapper userMapper,
                           UserRoleMapper userRoleMapper,
                           AuthQueryService authQueryService) {
        this.userMapper = userMapper;
        this.userRoleMapper = userRoleMapper;
        this.authQueryService = authQueryService;
    }

    @Override
    public Object login2(LoginParam model) {
        if (model == null || StringUtils.isEmpty(model.getUsername())
                || StringUtils.isEmpty(model.getPassword())) {
            return ResponseUtil.badArgument();
        }
        return ResponseUtil.ok(login(new LoginToken(LoginType.USER_PASSWORD,
                model.getUsername(), model.getPassword())));
    }

    private Object login(LoginToken token) {
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
        return subject.getSession().getId();
    }

    @Override
    public Object logout() {
        Subject curUser = SecurityUtils.getSubject();
        curUser.logout();

        return ResponseUtil.unlogin();
    }

    @Override
    public Object showMe() {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        user.setPassword(null);

        UserInfo userInfo = new UserInfo();
        userInfo.setUser(user);

        List<Role> rolesForUser = authQueryService.queryRolesByUser(user.getId());
        List<String> roles = rolesForUser.stream().map(ru -> {
            String role = ru.getId() == RoleEnum.ADMIN.getType() ? "admin" : "subscriber";
            return role;
        }).collect(Collectors.toList());

        userInfo.setRoles(roles);
        List<String> permissions = new ArrayList<>();
        userInfo.setPermissions(permissions);
        //return ResponseUtil.ok(userInfo);
        return userInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object register(RegisterParam model) throws BizException {
        // 参数校验
        if (model == null || !ArgumentUtil.notEmpty(model.getUsername(),
                 model.getPassword())) {
            return ResponseUtil.badArgument();
        }
        // 判断用户名是否存在
        UserExample example = new UserExample();
        example.createCriteria().andDeletedEqualTo(false)
                .andUsernameEqualTo(model.getUsername());
        List<User> list = userMapper.selectByExample(example);
        if (list.size() > 0) {
            throw new BizException(UserConstant.USERNAME_EXIST_CODE,
                    UserConstant.USERNAME_EXIST_ERROR);
        }
        User user = new User();
        BeanUtils.copyProperties(model, user);
        /*
        // 加密密码并写入新用户
        user.setPassword(PasswordUtil.encode(model.getPassword()));
        */
        user.setPassword(model.getPassword());
        user.setAddTime(LocalDateTime.now());
        user.setStatus(UserStatusEnum.UN_CHECK.getStatus());
        userMapper.insertSelective(user);

        //往user_role表中插入数据
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(RoleEnum.SUBSCRIBER.getType());
        userRole.setAddTime(LocalDateTime.now());
        userRoleMapper.insertSelective(userRole);

        user = userMapper.selectByPrimaryKey(user.getId());
        // 抹去密码，通常密码不需要展示
        user.setPassword(null);
        return ResponseUtil.ok(user);
    }

    @Override
    public Object login(LoginParam user) throws BizException {
        // 参数校验
        if (user == null || !ArgumentUtil.notEmpty(user.getUsername(),
                user.getPassword())) {
            return ResponseUtil.badArgument();
        }
        // 密码校验
        UserExample example = new UserExample();
        example.createCriteria().andDeletedEqualTo(false)
                .andUsernameEqualTo(user.getUsername());
        User model = userMapper.selectOneByExample(example);
        if (model == null) {
            throw new BizException(UserConstant.USERNAME_NOT_EXIST_CODE,
                    UserConstant.USERNAME_NOT_EXIST_ERROR);
        }

        Integer status = model.getStatus();
        if (UserStatusEnum.UN_CHECK.getStatus().equals(status)) {
            return ResponseUtil.fail(200, "您的账号正在审核，请耐心等待一下，待会儿登录~");
        } else if (UserStatusEnum.REFUSE.getStatus().equals(status)) {
            return ResponseUtil.fail(200, "对不起，您申请的账号未通过审核，无法登录本系统！");
        }
        // 下面这句为加密后的判断
        // !PasswordUtil.matchPwd(user.getPassword(), model.getPassword())
        if (!StringUtils.equals(user.getPassword(), model.getPassword())) {
            throw new BizException(UserConstant.USER_INVALID_CODE,
                    UserConstant.USER_INVALID_ERROR);
        }
        model.setPassword(null);
        return ResponseUtil.ok(model);
    }


    @Override
    public  Object getRouters(Integer userId) {
        List<Perm> memuPerms = authQueryService.queryMenusByUser(userId);
        List<Router> routers = memuPerms.stream().map(menu -> {
            Router r = new Router();
            r.setId(menu.getId());
            r.setComponent(LAYOUT);
            r.setAlwaysShow(true);
            Meta meta = new Meta(menu.getName());
            r.setMeta(meta);
            r.setPath(menu.getPermUrl());
            r.setName(menu.getRemark());
            return r;
        }).collect(Collectors.toList());

        routers.forEach(r -> {
            List<Perm> perms = authQueryService.queryPermsByMenu(r.getId());
            List<ChildrenRouter> children = perms.stream().map(p -> {
                ChildrenRouter cr = new ChildrenRouter();
                cr.setName(p.getRemark());
                cr.setComponent(p.getPermUrl());
                cr.setPath(p.getPermUrl().replace(r.getPath(), ""));
                Meta meta = new Meta(p.getName());
                cr.setMeta(meta);
                return cr;
            }).collect(Collectors.toList());
            r.setChildren(children);
        });

        return ResponseUtil.ok(routers);
    }

}
